use syn::{Expr, LitBool, LitFloat, LitInt, LitStr};

use crate::{error::Error, from_expr::FromExpr, value_parser::UnnamedFieldParser};
use syn::Result;

impl FromExpr for String {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Str(lit_str) = &lit.lit {
                return Ok(lit_str.value());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for i32 {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Int(lit_int) = &lit.lit {
                return lit_int.base10_parse();
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for u32 {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Int(lit_int) = &lit.lit {
                return lit_int.base10_parse();
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for bool {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Bool(lit_bool) = &lit.lit {
                return Ok(lit_bool.value());
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl FromExpr for f32 {
    fn from_expr(expr: &Expr) -> Result<Self> {
        if let Expr::Lit(lit) = expr {
            if let syn::Lit::Float(lit_float) = &lit.lit {
                return lit_float.base10_parse();
            }
        }
        Err(Error::unexpected_expr_type(expr).into())
    }
}

impl UnnamedFieldParser for String {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: LitStr = stream.parse()?;
        Ok(lit.value())
    }
}
impl UnnamedFieldParser for Option<String> {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: Option<LitStr> = stream.parse()?;
        Ok(lit.map(|lit| lit.value()))
    }
}

impl UnnamedFieldParser for i32 {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: LitInt = stream.parse()?;
        lit.base10_parse()
    }
}
impl UnnamedFieldParser for Option<i32> {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: Option<LitInt> = stream.parse()?;
        if let Some(lit) = lit {
            let value = lit.base10_parse()?;
            return Ok(Some(value));
        }
        Ok(None)
    }
}
impl UnnamedFieldParser for u32 {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: LitInt = stream.parse()?;
        lit.base10_parse()
    }
}
impl UnnamedFieldParser for Option<u32> {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: Option<LitInt> = stream.parse()?;
        if let Some(lit) = lit {
            let value = lit.base10_parse()?;
            return Ok(Some(value));
        }
        Ok(None)
    }
}
impl UnnamedFieldParser for f32 {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: LitFloat = stream.parse()?;
        lit.base10_parse()
    }
}
impl UnnamedFieldParser for Option<f32> {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: Option<LitFloat> = stream.parse()?;
        if let Some(lit) = lit {
            let value = lit.base10_parse()?;
            return Ok(Some(value));
        }
        Ok(None)
    }
}
impl UnnamedFieldParser for bool {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: LitBool = stream.parse()?;
        Ok(lit.value())
    }
}
impl UnnamedFieldParser for Option<bool> {
    fn parse(stream: syn::parse::ParseStream) -> syn::Result<Self> {
        let lit: Option<LitBool> = stream.parse()?;
        Ok(lit.map(|lit| lit.value()))
    }
}
